﻿/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#include "Ucop/Util/Application.h"
#include <cassert>
#include <csignal>
#include "Ucop/Exception.h"
#include "Ucop/ErrorHandler.h"
#include "Ucop/Util/Option.h"

using Ucop::Util::Option;


namespace Ucop {
namespace Util {

    Application *Application::_Myinstance = NULL;

    Application* Application::instance(void)
    {
        UCOP_ASSERT(_Myinstance);
        return _Myinstance;
    }

    Application::Application(const Char* _AppName /* = _L("Application") */)
        : _Myname(_AppName)
        , _Myarguemnts()
        , _Myoptions()
        , _MyupTime(0)
        , _MyatExit()
    {
        UCOP_ASSERT(!_Myinstance);
        _Myinstance = this;
    }

    Application::~Application(void)
    {

    }

    int Application::Run(int _Argc, Char* _Argv[])
    {
        int rc = EXIT_OK;

        do
        {
            try
            {
                /* Initialize application */
                rc = _Initialize(_Argc, _Argv);
                if (rc != EXIT_OK) {
                    break;
                }
                /* Get application startup time */
                ::time(&_MyupTime);
                /* execute */
                rc = Main(_Myarguemnts);
            }
            catch (Exception& e)
            {
                ErrorHandler::HandleException(e);
            }
            catch (std::exception& e)
            {
                ErrorHandler::HandleException(e);
            }
            catch (...)
            {
                ErrorHandler::HandleSystemException();
            }

        } while (false);

        /* Destroy */
        _Uninitialize();
        return rc;
    }

    bool Application::HookSignal(int _Signal, bool _Ignore /* = false */)
    {
        if (!_Ignore) {
            return (::signal(_Signal, &(Application::_SignalHandler)) != SIG_ERR);
        } else {
            return (::signal(_Signal, SIG_IGN) != SIG_ERR);
        }
    }

    void Application::UnhookSignal(int _Signal)
    {
        UCOP_ASSERT(::signal(_Signal, NULL) != SIG_ERR);
    }

    void Application::OnDefineOptions(OptionSet& _Options)
    {
        /* Help */
        _Options.AddOption(Option(_L("help"), _L("h"), _L("show usage"))
            .IsRequired(false)
            .HasArg(false));
    }

    int Application::OnOption(const String& _Name, const String& _Arg)
    {
        if (_Name.compare(_L("help")) == 0) {
            _ShowUsage();
            return EXIT_USAGE;
        }
        return EXIT_OK;
    }

    void Application::OnSignal(int _Signal)
    {

    }

    int Application::_Initialize(int argc, Char* argv[])
    {
        /* Process command line arguments */
        for (int x = 1; x < argc; ++x) {
            _Myarguemnts.push_back(argv[x]);
        }
        OnDefineOptions(_Myoptions);
        _Myoptions.Process(_Myarguemnts);
        OptionSet::const_iterator iter = _Myoptions.begin();
        for (; iter != _Myoptions.end(); ++iter)
        {
            if (!iter->IsValid())
            {
                if (iter->IsRequired()) {
                    return EXIT_USAGE;
                }
                continue;
            }

            int rc = OnOption(iter->name(), iter->value());
            if (rc != EXIT_OK) {
                return rc;
            }
        }

        return OnInitialize();
    }

    void Application::_Uninitialize(void)
    {
        OnUninitialize();
    }

    void Application::_ShowUsage(void)
    {
        _Lprintf(_L("%s USAGE\n"), _Myname);
        OptionSet::const_iterator iter = _Myoptions.begin();
        for (; iter != _Myoptions.end(); ++iter)
        {
            _Lprintf(_L("--%s,\t-%s\t\t\t%s\n"), 
                iter->name().c_str(), iter->GetShortName().c_str(), iter->description().c_str());
        }
        _Lprintf(_L("\n"));
    }

    void Application::_SignalHandler(int _Signal)
    {
        try
        {
            instance()->OnSignal(_Signal);
        }
        catch (LogicException& e)
        {
        	ErrorHandler::HandleException(e);
        }
        catch (std::exception& e)
        {
            ErrorHandler::HandleException(e);
        }
        catch (...)
        {
            ErrorHandler::HandleSystemException();
        }
    }

}}